/*
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.
*/
package com.jorritdevries.console
{
	import flash.events.Event;
	import flash.utils.getTimer;

	/**
	 * FPSCalculator is a utility class providing methods for obtaining
	 * rendering speed properties, such as the number of frames per second
	 * truely rendered by the Flash Player, or the duration of a single frame.
	 * 
	 * Since rendering speeds differ on every platform, depending on CPU
	 * speed of the host, display refresh rates and the set frame rate of the
	 * main SWF file (the so-called stage owner) this tool provides valuable
	 * information regarding rendering speed.
	 * @author jorrit@jorritdevries.com
	 */
	public class FPSCalculator
	{
		private static var msInstance:FPSCalculator = null;
		
		private var mTimeSinceLastFrame:Number;
		private var mCurrentTime:int;
		private var mTotalTime:int;
		private var mTotalFrames:uint;
		private var mCalcTime:int;
		private var mIsInitialised:Boolean;
		
		/**
		 * Creates the sole instance of the FPSCalculator class.
		 * @param enforcer SingletonEnforcer object to prevent this class
		 * from being instantiated.
		 * @private
		 */
		public function FPSCalculator(enforcer:SingletonEnforcer)
		{
			if (!enforcer)
			{
				throw new Error("FPSCalculator can not be instantiated.");
			}
		}
		
		/**
		 * Returns the sole instance of the FPSCalculator class.
		 * @return The sole instance of the FPSCalculator class.
		 */
		public static function getInstance():FPSCalculator
		{
			if (!msInstance)
			{
				msInstance = new FPSCalculator(new SingletonEnforcer());
			}
			return msInstance;
		}
		
		/**
		 * Initialises and resets the values used for calculating frame times
		 * and the number of frames per second.
		 * <p>Call this at least one time at the start of the calculations.</p>
		 */
		public function initialise():void
		{
			mTimeSinceLastFrame = 0;
			mTotalFrames = 0;
			mCurrentTime = mTotalTime = 0;
			mCalcTime = getTimer();
			mIsInitialised = true;
		}
		
		/**
		 * Calculates rhe time since the last call to this operation and calculates
		 * the obtainable data (frames per second and current frame time).
		 * <p>This operation should be called by adding the function as a listener
		 * to Event.ENTER_FRAME events of the stage. By setting a default value of
		 * <code>null</code>, we allow this operation to be called directly as well.<p>
		 * <p><strong>Note</strong>:This operation will do nothing if <code>initialise()</code>
		 * has not been called.</p>
		 * @see #initialise
		 * @see #getTimeSinceLastFrame
		 * @see #getCurrentFPS
		 * @see #getAverageFPS
		 */
		public function update(e:Event = null):void
		{
			if (mIsInitialised)
			{
				var currTime:Number = getTimer();
				mTimeSinceLastFrame = currTime - mCurrentTime;
				mCurrentTime = currTime;
				
				// Used for calculating average FPS
				mTotalTime += mTimeSinceLastFrame;
				mTotalFrames++;
			}
		}
		
		/**
		 * Obtains the time since the last frame. This is calculated by calling
		 * the <code>update()</code> operation on every Event.ENTER_FRAME
		 * @return The time since the last frame in milliseconds.
		 * @see #update
		 */
		public function get timeSinceLastFrame():Number
		{
			return mTimeSinceLastFrame;
		}
		
		/**
		 * Returns the current number of frames rendered per second.
		 * @return The current number of frames rendered in frames/second.
		 */
		public function get currentFPS():Number
		{
			return (1000 / mTimeSinceLastFrame);
		}
		
		/**
		 * Returns the average frames rendered per second since <code>initialise()</code> 
		 * has been called.
		 * @return The average number of frames rendered in frames/second.
		 * @see #initialise
		 */
		public function get averageFPS():Number
		{
			return ((mTotalFrames * 1000) / mTotalTime);
		}
	}
	
}

internal class SingletonEnforcer {}